package main

import (
	"fmt"
	"io"
	"os"
	"testing"
)

/*
Copy函数用于将数据从源（io.Reader）复制到目标（io.Writer）。
它会持续复制直到源中的数据全部读取完毕或发生错误，并返回复制的字节数和可能的错误

func Copy(dst io.Writer, src io.Reader) (written int64, err error)
其中dst 为目标写入器，用于接收源数据；src则是源读取器，用于提供数据。
*/

/*
io.Copy基本实现原理如下，首先创建一个缓冲区，用于暂存从源Reader读取到的数据。然后进入一个循环，
每次循环从源Reader读取数据，然后存储到之前创建的缓冲区，之后再写入到目标Writer中。不断重复这个过程，
直到源Reader返回EOF，此时代表数据已经全部读取完成，io.Copy也完成了从源Reader往目标Writer拷贝全部数据的工作。
*/
func main() {
	sourceFile := "source.txt"
	destinationFile := "destination.txt"

	// 打开源文件
	src, err := os.Open(sourceFile)
	if err != nil {
		fmt.Println("无法打开源文件:", err)
		return
	}
	// 调用Close方法
	defer src.Close()

	// 创建目标文件
	dst, err := os.Create(destinationFile)
	if err != nil {
		fmt.Println("无法创建目标文件:", err)
		return
	}
	// 调用Close 方法
	defer dst.Close()

	// 执行文件复制
	_, err = io.Copy(dst, src)
	if err != nil {
		fmt.Println("复制文件出错:", err)
		return
	}

	fmt.Println("文件复制成功!")
}

//考虑性能问题
/*
io.Copy 函数默认使用一个32KB大小的缓冲区来复制数据，如果我们处理的是大型文件，亦或者是高性能要求的场景，
此时是可以考虑直接使用io.CopyBuffer 函数，自定义缓冲区大小，以优化复制性能。而io.Copy和io.CopyBuffer
底层其实都是调用io.copyBuffer 函数的，二者底层实现其实没有太大的区别
*/
func BenchmarkCopyWithBufferSize(b *testing.B) {
	// 本地运行时, 文件大小为 100 M
	filePath := "largefile.txt"
	bufferSizes := []int{32 * 1024, 64 * 1024, 128 * 1024} // 不同的缓冲区大小

	for _, bufferSize := range bufferSizes {
		b.Run(fmt.Sprintf("BufferSize-%d", bufferSize), func(b *testing.B) {
			for n := 0; n < b.N; n++ {
				src, _ := os.Open(filePath)
				dst, _ := os.Create("destination.txt")

				buffer := make([]byte, bufferSize)
				_, _ = io.CopyBuffer(dst, src, buffer)

				_ = src.Close()
				_ = dst.Close()
				_ = os.Remove("destination.txt")
			}
		})
	}
}

//使用io.Copy 函数默认的 32KB 缓冲区，而较大的文件可能需要更大的缓冲区来提高性能。通过合理选择缓冲区大小，
//可以获得更高效的文件复制操作。
